package com.evzgaga.evzrecon.pluginmanager;

import com.evzgaga.evzrecon.util.CallbackInfo;
import com.evzgaga.evzrecon.annotations.runtime.CallbackHandlerAnnotationAnalyzer;
import com.evzgaga.evzrecon.annotations.runtime.ChatCommandAnnotationAnalyzer;
import com.evzgaga.evzrecon.annotations.Plugin;
import java.net.URL;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Bastien
 */
public class PluginLoader {
    private static final String PLUGIN_CONFIGURATION_PATH = "!/META-INF/plugin.properties";

    private JarClassLoader jarClassLoader = new JarClassLoader();
    private CallbackHandlerAnnotationAnalyzer callbackHandlerProcessor = new CallbackHandlerAnnotationAnalyzer();
    private ChatCommandAnnotationAnalyzer chatCommandProcessor = new ChatCommandAnnotationAnalyzer();

    public Object loadPlugin(String pluginPath) {
        String entryPointName = findPluginEntryPoint(pluginPath);
        return instantiateEntryPoint(pluginPath, entryPointName);
    }
    
    public Map<String, CallbackInfo> getInterestedCallbacksAndListeners(Object plugin) {
        return callbackHandlerProcessor.process(plugin);
    }

    public Map<String, CallbackInfo> getInterestedChatCommandHandlersAndListeners(Object plugin) {
        return chatCommandProcessor.process(plugin);
    }

    public boolean isValidPlugin(String pluginPath) {
        boolean isValidPlugin = false;

        try {
            String entryPoint = findPluginEntryPoint(pluginPath);

            isValidPlugin = entryPoint != null;
        } catch (InvalidPluginException ex) {
            Logger.getLogger(PluginLoader.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
        }

        return isValidPlugin;
    }
    
    protected String findPluginEntryPoint(String pluginPath) throws InvalidPluginException {
        Properties properties = new Properties();
        
        try {
            properties.load(new URL("jar:file://" + pluginPath + PLUGIN_CONFIGURATION_PATH).openStream());
        } catch (Exception ex) {
            throw new InvalidPluginException("Could not load plugin located in jar " + pluginPath, ex);
        }
        
        return properties.getProperty("plugin.entry.point");
    }

    protected Object instantiateEntryPoint(String pluginPath, String entryPointName) throws InvalidPluginException {
        Object entryPointInstance;
        
        try {
            jarClassLoader.loadJar(pluginPath);
            entryPointInstance = jarClassLoader.loadClass(entryPointName).newInstance();
        } catch (Exception ex) {
            throw new InvalidPluginException("Could not instantiate plugin's entry point " + entryPointName, ex);
        }
        
        if (entryPointInstance.getClass().getAnnotation(Plugin.class) != null) {
            return entryPointInstance;
        } else {
            throw new InvalidPluginException("Declared entry point does not have the @Plugin annotation");
        }
    }
}
